package anc.tankshooter.models;

import org.andengine.entity.sprite.AnimatedSprite;

import anc.tankshooter.GameSetting;
import anc.tankshooter.map.GameMap;
import anc.tankshooter.models.Bullet.BulletType;
import anc.tankshooter.ui.ResourcesManager;


/**
 * TANK
 * Tất cả các loại xe tăng luôn chạy theo từng ô
 * @author tauitdnmd
 *
 */
public abstract class ITank extends IDymanicObject {
	
	/**
	 * Hiển thị hiệu ứng tàng hình.
	 */
	private AnimatedSprite mBlindEffect;
	private boolean mIsBlind;
	private float mMaxTimeBlind,mTimeBlindRemain;
	private boolean mIsFindding;
	public boolean isMoving;
	
	public boolean mIsAutoShoot;
	
	protected boolean isShockBack;
	protected int nPX, nPY; // Luu vi tri tiep theo cua xe tang.
	protected ITank mTargetTank;
	/**
	 * Bán kính tìm kiếm xe tăng để tiêu diệt
	 */
	protected float mSearchRange;
	private BulletType mBulletType;
	
	
	public ITank(float pX, float pY) {
		super(pX, pY, ResourcesManager.getInstance().mTankTexture);
		
		nPX = (int) (pX / 32);
		nPY = (int) (pY / 32);
		isMoving = false;
		isShockBack = false;
		mIsAutoShoot = false;
		mTargetTank=null;
		mBlindEffect = new AnimatedSprite(0, 0,  ResourcesManager.getInstance().mInvisibleEffectTexture,ResourcesManager.getInstance().mVertexManager);
		mBlindEffect.animate(100, true);
		mBlindEffect.setX(getCenterX()-mBlindEffect.getWidth()/2); mBlindEffect.setY(getCenterY()-mBlindEffect.getHeight()/2);
		
		startBlind(true);
		setBulletType(BulletType.FIRE);
	}
	
	public int getNPX(){
		return nPX;
	}
	public int getNPY(){
		return nPY;
	}
	
	public boolean findTarget(ITank targetTank){
		boolean isTarget = false;
		mTargetTank = null;
		if(!targetTank.isBlind() && !isFindding()){
			float px = this.getCenterX();
			float py = this.getCenterY();
			Rect rect = this.getBound();
			float dx = targetTank.getCenterX() - px;
			float dy = targetTank.getCenterY() - py;
			isTarget = (dx*dx + dy*dy) <= (this.mSearchRange*this.mSearchRange);
			if(isTarget){
				mTargetTank = targetTank;
			}
		}
		return isTarget;
	}
	
	
	/**
	 * Kiểm tra xem có thể di chuyển tới ô
	 * kế tiếp hay không. Nếu có thể thì thực hiện di chuyển tới ô đó. 
	 * @param gmap
	 */
	public boolean checkMove(GameMap gmap){
		
		int nx  = (int)(mX/GameMap.TITLE_WIDTH);
		int ny  = (int)(mY/GameMap.TITLE_HEIGHT);
		
		switch (mDir) 
		{
			case UP:
				ny--;
				break;
			case RIGHT:
				nx++;
				break;
			case DOWN:
				ny++;
				break;
			case LEFT:
				nx--;
				break;
		}
		
		if(nx >= 0 && nx < GameMap.MAP_COLUMNS && 
				ny >= 0 && ny < GameMap.MAP_ROWS && 
				gmap.getMatrix()[ny][nx]==0)
		{
			nPX = nx; nPY = ny;
			return true;
		}
		
		return false;
	}
	
	/**
	 * Kiểm tra xem có hướng nào đi được hay không
	 * @param gmap
	 * @return
	 */
	public boolean hasMovingDirection(GameMap gmap){
		boolean isSuccess = false;
		int x = nPX = (int)(mX/GameMap.TITLE_WIDTH);
		int y = nPY = (int)(mY/GameMap.TITLE_HEIGHT);
		for( int i=0;!isSuccess && i<4;i++){
			int nx = x + GameMap.jv[i];
			int ny = y + GameMap.iv[i];
			if(nx >= 0 && nx < GameMap.MAP_COLUMNS && 
					ny >= 0 && ny < GameMap.MAP_ROWS && 
					gmap.getMatrix()[ny][nx]==0)
			{
				isSuccess = true;
			}
		}
		return isSuccess;
	}
	
	@Override
	protected void onManagedUpdate(float pSecondsElapsed) {
		mBlindEffect.setX(getCenterX()-mBlindEffect.getWidth()/2); mBlindEffect.setY(getCenterY()-mBlindEffect.getHeight()/2);
		super.onManagedUpdate(pSecondsElapsed);
	}
	
	@Override
	public void onUpdate(GameMap map, float elapseSecond) {
		
		if(mIsBlind){
			if(mTimeBlindRemain<=0) {
				if(mBlindEffect.hasParent())
					mBlindEffect.detachSelf();
				mTimeBlindRemain = mMaxTimeBlind;
				if(this.getParent()!=null)
					this.getParent().attachChild(mBlindEffect);
			} else {
				mTimeBlindRemain-=elapseSecond;
				mTimeBlindRemain = mTimeBlindRemain<=0?0:mTimeBlindRemain;
				mIsBlind = !( mTimeBlindRemain <=0);
				if(!mIsBlind){
					mBlindEffect.detachSelf();
				}
			}
		}
		
		if(isMoving)
		{
			float dx =Math.abs( mMoveVector[0] * elapseSecond);
			float dy =Math.abs( mMoveVector[1] * elapseSecond);
			
			move(elapseSecond);
			//Kiem tra xe tang toi duoc vi tri tiep theo hay chua
			float x = nPX * getWidth();
			float y = nPY * getHeight();
			if(Math.abs(mX - x) <= dx && Math.abs(mY - y) <= dy)
			{
				this.setPosition(nPX * getWidth(), nPY * getHeight());
				isMoving = false;
			}
		}
		/*
		if(isShockBack) {
			this.setPosition(this.mX - (mMoveVector[0]>0?5:0), this.mY - (mMoveVector[1]>0?5:0));
			if(Math.abs( mX - nPX * getWidth()) > getWidth() / 5 || 
			  Math.abs( mY - nPY * getHeight()) > getHeight() / 5)
			{
				isShockBack = false;
				isMoving = true;
			}
		}*/
	}
	
	@Override
	public void setDir(MovingDirection dir)
	{
		this.mDir=dir;
		switch(mDir){
		case UP:
			this.mMoveVector[0]=0; this.mMoveVector[1]=-this.mMoveSpeed;
			this.setRotation(-90);
			break;
		case RIGHT:
			this.mMoveVector[0]= this.mMoveSpeed; this.mMoveVector[1]=0;
			this.setRotation(0);
			break;
		case DOWN:
			this.mMoveVector[0]= 0; this.mMoveVector[1]= this.mMoveSpeed;
			this.setRotation(90);
			break;
		case LEFT:
			this.mMoveVector[0]= - this.mMoveSpeed; this.mMoveVector[1]=0;
			this.setRotation(-180);
			break;
		}
	}
	
	/**
	 * Reset thông số
	 * nPx , nPy
	 * 
	 */
	@Override
	public void reset() {
		nPX = (int)(mX/GameMap.TITLE_WIDTH);
		nPY = (int)(mY/GameMap.TITLE_HEIGHT);
		mIsAutoShoot=false;
		mIsDie=false;
		isMoving=false;
		isShockBack=false;
		mTargetTank = null;
		startBlind(true);
	}
	
	/**
	 * Bắn 1 viên đạn
	 * @return
	 */
	public Bullet shoot() 
	{
		float x=getCenterX();
		float y=getCenterY();
		
		switch (mDir) 
		{
			case UP:
				x = getX();
				y -= getHeight()/2 - 5;
				break;
			case RIGHT:
				x -= getWidth()/2 - 5;
				y = getY();
				break;
			case DOWN:
				x = getX();
				y -= getHeight()/2 - 5;
				break;
			case LEFT:
				x -= getWidth()/2 - 5;
				y = getY();
				break;
		}
		Bullet b = new Bullet(x, y, ResourcesManager.getInstance().mBulletTexture);
		b.setDir(getDir());
		b.setShooter(this);
		b.setType(this.getBulletType());
		
		ResourcesManager.getInstance().playSound(ResourcesManager.typeSound.SHOOT);
		if(isShockBack == false)
			isShockBack = true;
		mIsAutoShoot = false;
		return b;
	}
	
	public Bullet shoot(float x,float y) 
	{
		Bullet b = new Bullet(x, y, ResourcesManager.getInstance().mBulletTexture);
		b.setDir(getDir());
		b.setShooter(this);
		b.setType(this.getBulletType());
		
		ResourcesManager.getInstance().playSound(ResourcesManager.typeSound.SHOOT);
		if(isShockBack == false)
			isShockBack = true;
		mIsAutoShoot = false;
		return b;
	}
	
	public float[] shootAt() 
	{
		float x=getCenterX();
		float y=getCenterY();
		
		switch (mDir) 
		{
			case UP:
				x = getX();
				y -= getHeight()/2 - 5;
				break;
			case RIGHT:
				x -= getWidth()/2 - 5;
				y = getY();
				break;
			case DOWN:
				x = getX();
				y -= getHeight()/2 - 5;
				break;
			case LEFT:
				x -= getWidth()/2 - 5;
				y = getY();
				break;
		}
		return new float[]{x,y};
	}

	@Override
	public Rect getBound() {
		mRectBound.mLeft=getX();
		mRectBound.mTop=getY();
		mRectBound.mRight=mRectBound.mLeft+getWidth();
		mRectBound.mBottom=mRectBound.mTop+getHeight();
		return mRectBound;
	}

	public void startBlind(boolean isBlind,float maxSecond) {
		this.mIsBlind = isBlind;
		if(!mIsBlind){
			if(mBlindEffect.hasParent())
				mBlindEffect.detachSelf();
			mMaxTimeBlind=0;
			mTimeBlindRemain=0;
		} else {
			mMaxTimeBlind=maxSecond;
			mTimeBlindRemain=0;
		}
	}
	
	public void startBlind(boolean isBlind) {
		startBlind(isBlind, GameSetting.INVISIBLE_TIME);
	}
	
	public boolean isBlind() {
		return mIsBlind;
	}

	public float getTimeBlind() {
		return mTimeBlindRemain;
	}
	public float getMaxTimeBlind() {
		return mMaxTimeBlind;
	}

	public BulletType getBulletType() {
		return mBulletType;
	}

	public void setBulletType(BulletType mBulletType) {
		this.mBulletType = mBulletType;
	}

	public boolean isFindding() {
		return mIsFindding;
	}

	public void setIsFindding(boolean mIsFindding) {
		this.mIsFindding = mIsFindding;
	}
}
